/*
 * Copyright (c) 2017. 杭州端点网络科技有限公司.  All rights reserved.
 */

package com.jiantong.web.interceptors;

import com.google.common.base.Objects;
import com.jiantong.common.enums.UserType;
import com.jiantong.common.model.BaseLoginUser;
import com.jiantong.common.util.UserUtil;
import com.jiantong.user.cache.DepartmentCacher;
import com.jiantong.user.cache.OrganizationCacher;
import com.jiantong.user.ext.LoginUser;
import com.jiantong.user.model.DepartmentUser;
import com.jiantong.user.model.OrganizationUser;
import com.jiantong.user.model.User;
import com.jiantong.user.model.UserProfile;
import com.jiantong.user.service.*;
import com.jiantong.web.core.util.LoginUserMaker;
import io.terminus.boot.rpc.common.annotation.RpcConsumer;
import io.terminus.common.model.Response;
import io.terminus.common.utils.BeanMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * @author : panxin
 */
@Slf4j
@Component
public class WebLoginInterceptor extends HandlerInterceptorAdapter {

    // TODO 用户信息cache, 考虑关联信息是否做cache
    @RpcConsumer
    private UserReadService<User> userReadService;
    @RpcConsumer
    private OrganizationUserReadService organizationUserReadService;
    @RpcConsumer
    private DepartmentUserReadService departmentUserReadService;

    @Autowired
    private OrganizationCacher organizationCacher;
    @Autowired
    private DepartmentCacher departmentCacher;
    @RpcConsumer
    private UserProfileReadService userProfileReadService;
    @RpcConsumer
    private GovernmentUserDutyReadService governmentUserDutyReadService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("login interceptor, request = {}, \r\n response = {}", request, response);

        HttpSession session = request.getSession();
        if (session != null) {
            Object userIdInSession = session.getAttribute("userId");
            if (userIdInSession != null) {
                Long userId = Long.valueOf(userIdInSession.toString());
                Response<User> userResp = userReadService.findById(userId);
                if (!userResp.isSuccess()) {
                    log.warn("failed to find user where id = {},error code : {}", userId, userResp.getError());
                    return false;
                }

                User user = userResp.getResult();
                if (user != null) {
                    LoginUser loginUser = (LoginUser) wrapLoginUser(user);
                    UserUtil.putCurrentUser(loginUser);

                    log.info("user login succeed, loginUser = {}", loginUser);
                }
            }
        }
        return true;
    }

    private BaseLoginUser wrapLoginUser(User user) {
        BaseLoginUser baseLoginUser = LoginUserMaker.from(user);
        LoginUser loginUser = BeanMapper.map(baseLoginUser, LoginUser.class);

        Long userId = user.getId();
        Integer userType = user.getType();

        // 运营
        if (Objects.equal(userType, UserType.ADMIN.value())) {
            log.info("login user is platform admin, userId = {}", userId);
            return loginUser;
        }

        // 普通用户(政府、屠宰场、养殖场管理员)
        if (Objects.equal(userType, UserType.NORMAL.value())) {
            log.info("current is normal user, userId = {}", userId);
            return warpOrganizationUser(loginUser, userId);
        }

        // 普通员工(政府下的部门、分所、屠宰场、养殖场下面的普通员工)
        if (Objects.equal(userType, UserType.EMPLOYEE.value())) {
            log.info("current is normal employee, userId = {}", userId);
            return wrapDepartmentUser(loginUser, userId);
        }

        return loginUser;
    }

    private BaseLoginUser wrapDepartmentUser(LoginUser loginUser, Long userId) {
        Response<DepartmentUser> resp = departmentUserReadService.findDepartmentUserByUserId(userId);
        if (!resp.isSuccess()) {
            log.error(" failed to find department user by user id = {}, cause : {}", userId, resp.getError());
            return loginUser;
        }
        DepartmentUser departmentUser = resp.getResult();
        loginUser.setDepartmentId(departmentUser.getDepartmentId());
        loginUser.setDepartmentName(departmentUser.getDepartmentName());
        loginUser.setDepartmentType(departmentUser.getDepartmentType());
        loginUser.setEmpType(departmentUser.getEmpType());
        Response<UserProfile> resp1 = userProfileReadService.findUserProfileById(userId);
        if(!resp1.isSuccess()){
            log.error(" failed to find user profile by user id = {}, cause : {}", userId, resp1.getError());
            return loginUser;
        }
        UserProfile userProfile = resp1.getResult();
        loginUser.setUserProfile(userProfile);
        return loginUser;
    }

    private BaseLoginUser warpOrganizationUser(LoginUser loginUser, Long userId) {
        Response<OrganizationUser> resp = organizationUserReadService.findOrganizationUserByUserId(userId);
        if (!resp.isSuccess()) {
            log.error(" failed to find organization user by user id = {}, cause : {}", userId, resp.getError());
            return loginUser;
        }
        OrganizationUser organizationUser = resp.getResult();
        loginUser.setOrganizationId(organizationUser.getOrganizationId());
        loginUser.setOrganizationName(organizationUser.getOrganizationName());
        loginUser.setOrganizationType(organizationUser.getOrganizationType());

        Response<UserProfile> resp1 = userProfileReadService.findUserProfileById(userId);

        if(!resp1.isSuccess()){
            log.error(" failed to find user profile by user id = {}, cause : {}", userId, resp1.getError());
            return loginUser;
        }
        UserProfile userProfile = resp1.getResult();
        loginUser.setUserProfile(userProfile);
        return loginUser;
    }
}
